home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / math / gle-3.000 / gle-3 / gle / tex.c < prev    next >
C/C++ Source or Header  |  1995-02-07  |  39KB  |  1,624 lines

  1. #include <stdlib.h>
  2. #include <ctype.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #ifndef unix
  7. #include <stdarg.h>
  8. #endif
  9. #include "glepro.h"
  10. #define false 0
  11. #define true (!false)
  12. #include "mygraph.h"
  13. #include <math.h>
  14. double emtof(char *s);
  15. int font_reset_parskip(void);
  16. int set_parskip(double v);
  17. int set_lineskip(double v);
  18. int ncat(char *a,char *b,int n);
  19. int pp_fntchar(int f, int c,int32 *out, int *lout);
  20. int polish_eval(char *s, double *x);
  21. int cmd_token(uchar **in,char *cmdstr);
  22. int set_base_size(void);
  23. int find_primcmd(char *cmd);
  24. int text_box(uchar *s,double width,int32 *tbuff, int32 *rplen);
  25. int cmd_param(uchar **inp,uchar *pm[],int pmlen[],int npm);
  26. int text_tomacro(uchar *in, uchar *out);
  27. int texint(char *s, int *i);
  28. int tex_presave(void);
  29. int tex_preload(void);
  30. int fsendstr(char *s, FILE *fout);
  31. int text_gprint(int32 *in,int ilen);
  32. int fftext_block(uchar *s,double width,int justify);
  33. void font_load(void);
  34. int tex_init(void);
  35. int g_get_font(int *i);
  36. int do_prim(uchar **in,int32 *out,int *lout);  /*  \frac{text}{text} */
  37. #define dbg if ((gle_debug & 1024)>0)
  38. extern int gle_debug;
  39. double text_endx,text_endy;
  40. /*----------------------------------------------------------------------*/
  41. /*              TeX Emulation routines                                  */
  42. /*----------------------------------------------------------------------*/
  43. #define FONTDEF extern
  44. #include "font.h"
  45. #include "tex.h"
  46. double linegap;
  47. /*----------------------------------------------------------------------*/
  48. struct def_table_struct {
  49.     struct def_table_struct *next;
  50.     char *name;
  51.     char *defn;
  52.     int npm;
  53. };
  54. typedef struct def_table_struct deftable;
  55.  
  56. /*----------------------------------------------------------------------*/
  57. int tex_def(char *name, char *defn,int npm);
  58. int tex_mathdef(char *name, int defn);
  59. int *tex_findmathdef(char *s);
  60. int tex_chardef(int c, char *defn);
  61. char *tex_findchardef(int c);
  62. deftable *tex_finddef(char *s) ;
  63. /*----------------------------------------------------------------------*/
  64. /*              Global variables for TEX emulation */
  65.  
  66. int fontfam[16][4];
  67. double fontfamsz[16][4];        /* 1=text,  2=script, 3=scriptscript */
  68. int famdef = -1;        /* dont use unless/until it is defined */
  69.  
  70. char *cdeftable[256];   /* Character macro's */
  71. uchar chr_code[256];    /* Character codes 1..9  */
  72. int chr_mathcode[256];  /* Character codes 1..9  */
  73. int chr_val[256];       /* Character values, or macro numbers */
  74. int chr_init;           /* Flag to initialize chr variables */
  75.  
  76. #define dp if (dont_print==false)
  77. int dont_print=0;
  78. int32 gt_pbuff[5000];
  79. int gt_plen;
  80. double gt_l,gt_r,gt_u,gt_d;
  81.  
  82. int tofont[9] = {0,2,2,1,1,0,0,0,0};
  83.  
  84. int p_fnt;
  85. double p_hei;
  86. double grphei[10];
  87. int grpfnt[10];
  88. int p_ngrp;
  89.  
  90. double base_size;
  91. int curstyle=6;
  92.  
  93. double stretch_factor=1;
  94. /*----------------------------------------------------------------------*/
  95.  
  96. union both {float f;int32 l;} bth;
  97. #define outlong(v) *(out+((*lout)++)) = v
  98. #define outfloat(v) bth.f = v; *(out+((*lout)++)) = bth.l
  99. #define chrwidth(d) ((*(fnt[p_fnt].chr))[d].wx)
  100. #define tofloat(fff) ((bth.l = fff),bth.f )
  101. #define tolong(fff) ((bth.f = fff),bth.l )
  102. #define checkfont if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt)
  103.  
  104. int set_stretch(double v);
  105. set_stretch(double v)
  106. {
  107.     stretch_factor = v;
  108. }
  109. set_base_size()
  110. {
  111.     g_get_hei(&base_size);
  112. }
  113. text_topcode(uchar *in, int32 *out, int *lout)      /*  passed a paragraph  */
  114. {
  115.     int skip_space;
  116.     float w;
  117.     uchar c,d,c2,d2;
  118.  
  119.     outlong(8);     /* set font size */
  120.     outfloat(p_hei);
  121.  
  122.  
  123.     while (c = *(in++)) {
  124.   dbg /* if (chr_code[c]>2) */ gprint("uchar %d, code %d  value %d \n",c,chr_code[c],chr_val[c]);
  125.       switch (chr_code[c]) {
  126.         case 10:
  127.         case 1: /* Normal character */
  128.         d = chr_val[c];
  129.         /* if next char is normal, then check for ligature and kern */
  130. norm_again:
  131.         w=0;
  132.         checkfont;
  133.         if (chr_code[*in]==1 || chr_code[*in]==10) {
  134.             if (char_lig(p_fnt,&d,chr_val[*in])) {
  135.                 in++;
  136.                 goto norm_again;
  137.             }
  138.             char_kern(p_fnt,d,chr_val[*in],&w);
  139.         }
  140.         outlong(1);
  141.         outlong(d | p_fnt*256);
  142.         dbg gprint("==char width %d %f %f \n",d,chrwidth(d),w);
  143.         if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt);              outfloat((chrwidth(d)+w)*p_hei);
  144.         skip_space = false;
  145.         break;
  146.         case 2: /* Single space */
  147.         if (skip_space) break;
  148.         skip_space = true;
  149.         outlong(2);
  150.         checkfont;
  151.         outfloat(fnt[p_fnt].space*p_hei);
  152.         outfloat(fnt[p_fnt].space_stretch*p_hei*10*stretch_factor);
  153.         outfloat(fnt[p_fnt].space_shrink*p_hei*10);
  154.         break;
  155.         case 3: /* Tab (for tabular) */
  156.         break;
  157.         case 4: /* 8Tab (verbatim) */
  158.         break;
  159.         case 5: /* \\ End of line */
  160.         skip_space = false;
  161.         outlong(5);
  162.         outlong(0);             /* space for x,y to be put */
  163.         outlong(0);
  164.         break;
  165.         case 6: /* \ Primitive Command (macro's already done) */
  166.         skip_space = false;
  167.         do_prim(&in,out,lout);
  168.         break;
  169.         case 7: /* { begin group */
  170.         skip_space = false;
  171.         grphei[++p_ngrp] = p_hei;
  172.         grpfnt[p_ngrp] = p_fnt;
  173.         break;
  174.         case 8: /* } end group */
  175.         skip_space = false;
  176.         if (p_ngrp<1) {
  177.             gprint("%s\n",in);
  178.             gprint("Too many end group brackets \n");
  179.             return;
  180.         }
  181.         p_hei = grphei[p_ngrp];
  182.         p_fnt = grpfnt[p_ngrp--];
  183.         font_load_metric(p_fnt);
  184.  
  185.         outlong(8); outfloat(p_hei);
  186.         break;
  187.         case 9: /* $^_ Macro (Done in macro expansion) */
  188.         skip_space = false;
  189.         break;
  190.         case 11: /* flag for end of paragraph */
  191.             skip_space = false;
  192.         outlong(10);
  193.         outlong(0);     /* space for x,y to be put */
  194.         outlong(0);
  195.         break;
  196.         default:
  197.         gprint("error, not valid character \n");
  198.       }
  199.     }
  200. }
  201. /* cmd_param(uchar **inp,char *(*pm)[],int (*pmlen)[],int npm) */
  202. int cmd_param(uchar **inp,uchar *pm[],int pmlen[],int npm)
  203. {
  204.     int gcnt=0,i;
  205.     uchar *in = *inp;
  206.     gcnt = 0;
  207.     for (i=0;i<npm;i++) {
  208.      pm[i] = in;
  209.      pmlen[i] = 0;
  210.       if (chr_code[*in]==7) { /* begin group */
  211.         pm[i] = ++in;
  212.         for (;*in!=0;in++) {
  213.             if (chr_code[*in]==7) gcnt++;
  214.             if (chr_code[*in]==8) {
  215.                 if (gcnt==0) break;
  216.                 gcnt--;
  217.             }
  218.         }
  219.         pmlen[i] = in - pm[i];
  220.         in++;
  221.       } else {
  222.         if (chr_code[*in]==6) { /* backslash look for non-alpha */
  223.             pm[i] = ++in;
  224.             if (isalpha(*pm[i])) {
  225.                 for (;*in!=0;in++) {
  226.                     if (!isalpha(*in)) {
  227.                         break;
  228.                     }
  229.                 }
  230.                 pmlen[i] = in - pm[i];
  231.             } else {
  232.                 pm[i] = in;
  233.                 pmlen[i] = 1;
  234.                 in++;
  235.             }
  236.         } else {
  237.             pm[i] = in;
  238.             pmlen[i] = 1;
  239.             in++;
  240.         }
  241.       }
  242.     }
  243.     *inp = in;
  244. }
  245. text_box(uchar *s,double width,int32 *tbuff, int32 *rplen)
  246. {
  247.     uchar *t,*r,*m,*p;
  248.     int i;
  249.     int plen=0;
  250.     char *workbuff;
  251.  
  252.     workbuff = myalloc(1000);
  253.     if (s==NULL) return;
  254.     if (*s==0) return;
  255.     if (chr_init==false) tex_init();
  256.     text_tomacro(s,UC workbuff);
  257.     plen = 0;
  258.     if (width==0) width = 400;
  259.     text_topcode(UC workbuff,tbuff,&plen);
  260.     text_wrapcode(tbuff,plen,width);
  261.     *rplen = plen;
  262.     myfree(workbuff);
  263. }
  264. topcode(char *s, int slen, double width, int32 **pbuff, int32 *plen, double *l,double *r,double *u,double *d)
  265. {
  266.     char schar;
  267.  
  268.     *pbuff = myalloc(1000);
  269.     g_init_bounds();
  270.     schar = s[slen];
  271.     s[slen] = 0;
  272.     text_box(UC s,width,*pbuff,plen);
  273.     s[slen] = schar;
  274.     g_get_bounds(l,d,r,u);
  275.     if (*l > *r) {*l=0; *r=0; *u=0; *d=0;}
  276.  
  277. }
  278.  
  279. #define p_sethei(hh) pp_sethei(hh,out,lout)
  280. #define p_hfill(hh) pp_hfill(hh,out,lout)
  281. #define p_move(x,y) pp_move(x,y,out,lout)
  282. #define p_fntchar(ff,cc) pp_fntchar(ff,cc,out,lout)
  283. #define p_mathchar(m) pp_mathchar(m,out,lout)
  284. #define p_pcode(pbuff,plen) pp_pcode(pbuff,plen,out,lout)
  285.  
  286. pp_move(double x, double y, int32 *out,int *lout)
  287. {
  288.     outlong(4);
  289.     outfloat(x);
  290.     outfloat(y);
  291. }
  292. pp_sethei(double h, int32 *out,int *lout)
  293. {
  294.     outlong(8);
  295.     outfloat(h);
  296.     p_hei = h;
  297. }
  298. pp_hfill(double h, int32 *out,int *lout)
  299. {
  300.     outlong(2);
  301.     outfloat(0.0);
  302.     outfloat(h*p_hei);
  303.     outfloat(h*p_hei);
  304. }
  305. int char_bbox_user(int p_fnt,int ix, double *x1,double *y1,double *x2,double *y2);
  306. char_bbox_user(int p_fnt,int ix, double *x1,double *y1,double *x2,double *y2)
  307. {
  308.     char_bbox(p_fnt,ix,x1,y1,x2,y2);
  309.     *x1 *= p_hei;
  310.     *x2 *= p_hei;
  311.     *y1 *= p_hei;
  312.     *y2 *= p_hei;
  313. }
  314. pp_mathchar(int m, int32 *out, int *lout)
  315. {
  316.     int mchar,mfam,mtyp;
  317.     int ix;
  318.     double x1,y1,x2,y2,reqhi,yc;
  319.     double oldhei;
  320.     oldhei = p_hei;
  321.     mchar = m & 0xff;
  322.     mfam = (m & 0xf00) / 0x100;
  323.     mtyp = (m & 0xf000) / 0x1000;
  324.     if (mtyp == 7  && famdef>=0) mfam = famdef;
  325.     if (mtyp == 7) mtyp = 0;
  326.     ix = 'b'; /* center on letter b */
  327.     char_bbox_user(p_fnt,ix,&x1,&y1,&x2,&y2);
  328.     reqhi = y2/2;
  329.     p_sethei(fontfamsz[mfam][tofont[curstyle]] * p_hei);
  330.     char_bbox_user(fontfam[mfam][tofont[curstyle]],mchar,&x1,&y1,&x2,&y2);
  331.     yc = (y2-y1)/2;
  332.     if (mtyp==1) pp_move(0,reqhi+yc-y2,out,lout);
  333.     p_fntchar(fontfam[mfam][tofont[curstyle]],mchar);
  334.     if (mtyp==1) pp_move(0,-(reqhi+yc-y2),out,lout);
  335.     p_sethei(oldhei);
  336. }
  337. #define mchrwidth(ddd) ((*(fnt[ff].chr))[ddd].wx)
  338. pp_fntchar(int ff, int ch, int32 *out,int *lout)
  339. {
  340.     if (fnt[ff].chr==NULL) font_load_metric(ff);
  341.     outlong(1);
  342.     if (ch==0) ch = 254;
  343.     outlong(ch | ff*256);
  344.     outfloat((mchrwidth(ch))*p_hei);
  345. }
  346. pp_pcode(int32 *pbuff, int plen, int32 *out,int *lout)
  347. {
  348.     int i;
  349.     out += *lout;
  350.     for (i=0;i<plen;i++) *out++ = *pbuff++;
  351.     *lout = *lout + plen;
  352. }
  353. cmd_param1(uchar **in,char *str1)
  354. {
  355.     union {char *s[4]; uchar *u[4];} pm;
  356.     int pmlen[4];
  357.     cmd_param(in,pm.u,pmlen,1);
  358.     ncpy(str1,pm.s[0],pmlen[0]);
  359. }
  360. cmd_param2(uchar **in,char *str1,char *str2)
  361. {
  362.     union {char *s[4]; uchar *u[4];} pm;
  363.     int pmlen[4];
  364.     cmd_param(in,pm.u,pmlen,(int) 2);
  365.     ncpy(str1,pm.s[0],pmlen[0]);
  366.     ncpy(str2,pm.s[1],pmlen[1]);
  367. }
  368. cmd_param3(uchar **in,char *str1,char *str2,char *str3)
  369. {
  370.     union {char *s[5]; uchar *u[5];} pm;
  371.     int pmlen[5];
  372.     cmd_param(in,pm.u,pmlen,3);
  373.     ncpy(str1,pm.s[0],pmlen[0]);
  374.     ncpy(str2,pm.s[1],pmlen[1]);
  375.     ncpy(str3,pm.s[2],pmlen[2]);
  376. }
  377.  
  378. do_prim(uchar **in,int32 *out,int *lout)  /*  \frac{text}{text} */
  379. {
  380.     int ci;
  381.     int ix,savefnt,newfnt;
  382.     static char cmdstr[20];
  383.     char str1[100],str2[100],str3[100];
  384.     double lef,wid,hei,dep,savehei,x;
  385.     int32 *pbuff=0;
  386.     int32 plen;
  387.     union {char *s[10]; uchar *u[10];} pm;
  388.     int pmlen[10];
  389.     int *m,i,k,j,n,npm;
  390.  
  391.     k = 0;
  392.  
  393.     cmd_token(in,cmdstr);   /* finds command name and parameters */
  394.     ci = find_primcmd(cmdstr);
  395.     if (ci==0) { /* then maybe its a mathchar */
  396.         m = tex_findmathdef(cmdstr);
  397.         if (m!=0) {
  398.             p_mathchar(*m);
  399.         } else {
  400.             gprint("Unrecognised control sequence {%s} \n",cmdstr);
  401.         }
  402.         return;
  403.     }
  404.     switch (ci) {
  405.       case tp_sup: /* \superscript{exp} */
  406.         cmd_param(in,pm.u,pmlen,1);
  407.         savehei = p_hei;
  408.         p_hei = p_hei * .7;
  409.         topcode(pm.s[0],pmlen[0],0.0,&pbuff,&plen,&lef,&wid,&hei,&dep);
  410.         p_move(0,0.8*p_hei);
  411.         p_pcode(pbuff,plen);
  412.         p_move(0,-0.8*p_hei);
  413.         myfree(pbuff);
  414.         p_sethei(savehei);
  415.         break;
  416.       case tp_sub:
  417.         cmd_param(in,pm.u,pmlen,1);
  418.         savehei = p_hei;
  419.         p_hei = p_hei * .7;
  420.         topcode(pm.s[0],pmlen[0],0.0,&pbuff,&plen,&lef,&wid,&hei,&dep);
  421.         p_move(0,-0.3*p_hei);
  422.         p_pcode(pbuff,plen);
  423.         p_move(0,0.3*p_hei);
  424.         myfree(pbuff);
  425.         p_sethei(savehei);
  426.         break;
  427.       case tp_sethei: /* \sethei{exp} */
  428.         cmd_param1(in,str1);
  429.         p_sethei(emtof(str1));
  430.         break;
  431.       case tp_hfill: /* \sethei{exp} */
  432.         p_hfill(10.0);
  433.         break;
  434.       case tp_char:
  435.         cmd_param1(in,str1);
  436.         texint(str1,&ix);
  437.         p_fntchar(p_fnt,ix);
  438.         break;
  439.       case tp_chardef:  /* /chardef{a}{xxxxx} */
  440.         cmd_param2(in,str1,str2);
  441.         tex_chardef(str1[0],str2);
  442.         break;
  443.       case tp_ssfont:
  444.         k++;
  445.       case tp_sfont:
  446.         k++;
  447.       case tp_tfont:  /* \tfont{0}{cmr10}{.5}  */
  448.         cmd_param3(in,str1,str2,str3);
  449.         i = atoi(str1);  if (i>15) i = 1;
  450.         fontfam[i][k] = pass_font(str2);
  451.         fontfamsz[i][k] = emtof(str3);
  452.         break;
  453.       case tp_accent:  /* accent{texcmr}{123}{a} */
  454.         {
  455.         double wid2,hei2,lef2,dep2,ww,hh,h=0,cwid,cwid2;
  456.         int ix2;
  457.  
  458.         cmd_param3(in,str1,str2,str3);
  459.         savefnt = p_fnt;
  460.         newfnt = pass_font(str1);
  461.         texint(str2,&ix);
  462.         ix2 = str3[0];
  463.         char_bbox(newfnt,ix,&lef,&dep,&wid,&hei);
  464.         cwid = p_hei * ((*(fnt[newfnt].chr))[ix].wx);
  465.         char_bbox(p_fnt,ix2,&lef2,&dep2,&wid2,&hei2);
  466.         cwid2 = p_hei * ((*(fnt[p_fnt].chr))[ix2].wx);
  467.  
  468.         wid *= p_hei;  wid2 *= p_hei; hei *= p_hei; hei2 *= p_hei;
  469.         lef *= p_hei;  dep *= p_hei;
  470.         lef2 *= p_hei;  dep2 *= p_hei;
  471.         if (hei2>p_hei*(3.6/8.0)) h = hei2-p_hei*(3.6/8.0);
  472.  
  473.         ww = lef2+wid2;
  474.         p_fntchar(p_fnt,ix2);
  475.         p_move(-cwid2 + lef2 + wid2/2 -wid/2,h);  /* cwid2/2 - cwid/2 */
  476.         p_fntchar(newfnt,ix);        /* cwid2/2 + cwid/2 */
  477.         p_move(-cwid + cwid2 - lef2 - wid2/2 + wid/2,-h);
  478.         p_fnt = savefnt;
  479.         font_load_metric(p_fnt);
  480.         break;
  481.         }
  482.       case tp_def:
  483.         cmd_param1(in,str1); /* finds everything up to the #1#2 */
  484.         npm = 0;
  485.         while (**in == '#') {
  486.             (*in)++;
  487.             n = (*(*in)++) - '0';
  488.             if (n>0 && n<9) if (npm<n) npm=n;
  489.         }
  490.         cmd_param1(in,str2);
  491.         tex_def(str1,str2,npm);
  492.         break;
  493.       case tp_mathchardef:  /* /mathchardef */
  494.         cmd_param2(in,str1,str2);
  495.         texint(str2,&ix);
  496.         tex_mathdef(str1+1,ix);
  497.         break;
  498.       case tp_movexy:
  499.         cmd_param2(in,str1,str2);
  500.         p_move(emtof(str1),emtof(str2));
  501.         break;
  502.       case tp_rule:
  503.         cmd_param2(in,str1,str2);
  504.         outlong(6);
  505.         outfloat(emtof(str1));
  506.         outfloat(emtof(str2));
  507.         break;
  508.       case tp_mathchar:
  509.         cmd_param1(in,str1);
  510.         texint(str1,&ix);
  511.         p_mathchar(ix);
  512.         break;
  513.       case tp_mathcode:
  514.         cmd_param2(in,str1,str2);
  515.         texint(str2,&ix);
  516.         chr_mathcode[*str1] = ix;
  517.         break;
  518.       case tp_delcode:
  519.         cmd_param2(in,str1,str2);
  520.         texint(str2,&ix);
  521.         chr_mathcode[*str1] = ix;
  522.         break;
  523.       case tp_setfont:
  524.         cmd_param1(in,str1);
  525.         p_fnt = pass_font(str1);
  526.         font_load_metric(p_fnt);
  527.  
  528.         if (fnt[p_fnt].chr==NULL) font_load_metric(p_fnt);
  529.         break;
  530.       case tp_presave:
  531.         gprint("Saving definitions\n");
  532.         tex_presave();
  533.         break;
  534.       case tp_newline:
  535.         outlong(5);
  536.         outlong(0);             /* space for x,y to be put */
  537.         outlong(0);
  538.         break;
  539.       case tp_parskip:
  540.         cmd_param1(in,str1);
  541.         set_parskip(emtof(str1));
  542.         break;
  543.       case tp_setstretch:
  544.         cmd_param1(in,str1);
  545.         set_stretch(emtof(str1));
  546.         break;
  547.       case tp_lineskip:
  548.         cmd_param1(in,str1);
  549.         set_lineskip(emtof(str1));
  550.         break;
  551.       case tp_linegap:
  552.         cmd_param1(in,str1);
  553.         linegap = emtof(str1);
  554.         break;
  555.       case tp_frac:
  556.       case tp_delimiter:
  557.       case tp_left:
  558.       case tp_right:
  559.       case tp_defbegin:
  560.       case tp_nolimits:
  561.  
  562.       case tp_overbrace:
  563.       case tp_overline:
  564.       case tp_underbrace:
  565.       case tp_underline:
  566.         gprint("A valid GLE-TEX primitive which isn't implemented yet %d \n",ci);
  567.         break;
  568.       default:
  569.         gprint("An invalid GLE-TEX primitive %d \n",ci);
  570.         break;
  571.     }
  572. }
  573. #ifndef DJ
  574. double emtof(char *s)
  575. {       /* same as ATOF but if it sees EM then it multiplies by FONT HEI */
  576.     if (strstr(s,"sp")!=NULL) {
  577.         return atof(s)*fnt[p_fnt].space*p_hei;
  578.     }
  579.     if (strstr(s,"em")!=NULL) {
  580.         return atof(s)*p_hei*.75;
  581.     }
  582.     return atof(s);
  583. }
  584. #else
  585. double emtof(char *s)
  586. {       /* same as ATOF but if it sees EM then it multiplies by FONT HEI */
  587.     /* GLE32 doesn't interpret "-1em" but "-1 em"  a.r. */
  588.     char *ss;       /* is it allowed to overwrite s? */
  589.     double ret;
  590.  
  591.     ss = (char *) malloc((strlen(s)+1)*sizeof(char));
  592.     strcpy(ss,s);
  593.     if (strstr(ss,"sp")!=NULL) {
  594.         *strstr(ss,"sp") = '\0';
  595.         ret = atof(ss)*fnt[p_fnt].space*p_hei;
  596.         free(ss);
  597.         return ret;
  598.     }
  599.     if (strstr(ss,"em")!=NULL) {
  600.         *strstr(ss,"em") = '\0';
  601.         ret = atof(ss)*p_hei*.75;
  602.         free(ss);
  603.         return ret;
  604.     }
  605.     ret = atof(ss);
  606.     free(ss);
  607.     return ret;
  608. }
  609. #endif
  610.  
  611. texint(char *s, int *i) /* Reads an integer, or hex string (if $) */
  612. {
  613.     int32 j;
  614.     if (*s=='$') {
  615.         sscanf(s+1,"%lx",&j);
  616.         *i = j;
  617.     } else *i = atoi(s);
  618. }
  619. /*
  620.     Character Codes
  621.  
  622.     a..z            1       normal character
  623.     space           2       single space
  624.     <TAB>,&         3       Tab (as in tabular)
  625.     <8TAB>          4       TAB (as in verbatim)
  626.     <LF>,\\         5       End of line
  627.     \               6       Macro or command
  628.     {               7       Begin group
  629.     }               8       end group
  630.     $_^             9       Macro call
  631.             10      null
  632.     255             11      end of paragraph (crcr)
  633.     end of command, = first non alpha character
  634. */
  635.  
  636.  
  637.  
  638.  
  639. /*      Bounding Box ??
  640.  
  641.     1=char  font+char,x
  642.     2=move  x,stret,shrink                  throw away after cr
  643.     3=MOVE  x,0,0                           glue which has been set
  644.     4=MOVE  x,y                             solid move
  645.     5=newline,x,y
  646.     6=rule  x,y
  647.     10=color color
  648.     8=fontsz   fontsz
  649.     9=font   i
  650.     15=null
  651. */
  652. #define infloat(fff) ((bth.l = fff),bth.f)
  653.  
  654.  
  655. text_wrapcode(int32 *in,int ilen,double width)
  656. {
  657.     double cx=0,cy=0,p_hei,ax=0,x,y,cdep=0,chei=0;
  658.     int i,j,eat_glue,c,p_fnt,si,skline,saveii;
  659.     double totstretch=0,totshrink=0,ls=0,gap=0
  660.         ,last_y,last_x,lastdep,last_stret,last_shrink;
  661.     int32 *pcr=0,last_space=0;
  662.     double setlen;
  663.     dbg text_gprint(in,ilen);
  664.     ls = 0;
  665.     last_x = 0;
  666.     gap = 0;
  667.     last_y = 0;
  668.     lastdep = 0;
  669.     last_stret = 0;
  670.     last_shrink = 0;
  671.     dbg gprint("==wrap pcode, ilen = %d \n",ilen);
  672.  
  673.     dbg gprint("wrap pcode ilen=%d \n",ilen);
  674.     p_hei = 1;
  675.     si = 0;
  676.     for (i=0;i<ilen;i++) {
  677.       switch (*(in+i)) {
  678.         case 1: /* char     font+char,wx    */
  679.         eat_glue = false;
  680.         p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
  681.         font_load_metric(p_fnt);
  682.  
  683.         c = *(in+i) & 0x00ff;
  684.         if (cdep>cy+p_hei*((*(fnt[p_fnt].chr))[c].y1))
  685.             cdep=cy+p_hei*((*(fnt[p_fnt].chr))[c].y1);
  686.         if (chei<cy+p_hei*((*(fnt[p_fnt].chr))[c].y2))
  687.             chei=cy+p_hei*((*(fnt[p_fnt].chr))[c].y2);
  688. /*              gprint("chei=%f, cdep=%f \n",chei,cdep);   */
  689.  
  690.         cx += tofloat(*(in+ ++i));
  691.         ax = cx;
  692.         if (cx>width) {
  693.           if (last_space>si) {
  694.             dbg gprint("Call SET_GLUE  from %d, to %d \n",si,last_space);
  695.             set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
  696.             i = last_space;
  697.             *(in+i++) = 4;
  698.             *(in+i++) = tolong(-setlen);
  699.             if (pcr!=NULL) { /* put in last line feed now */
  700.                 y = last_y-ls;
  701.                 if ((y+chei+gap)>lastdep)
  702.                     y = lastdep-chei-gap;
  703.                 cy = y;
  704.                 *pcr = tolong(y);
  705.             }
  706.             font_get_lineskip(&ls,&gap);
  707.             pcr = (in+i++);   /* place to put line feed */
  708.             *(in+i) = 20;           /* null */
  709.             last_stret = 0;
  710.             last_shrink = 0;
  711.             totstretch = 0;
  712.             totshrink = 0;
  713.             lastdep = cdep;
  714.             last_y = cy;
  715.             cx = 0;
  716.             cy = 0;
  717.             si = i;
  718.             eat_glue = true;
  719.           }
  720.         }
  721.         break;
  722.         case 2: /* move     x,stretch,shrink */
  723.         last_space = i;
  724.         last_x = ax;
  725.         last_y = cy;
  726.         last_stret = totstretch;
  727.         last_shrink = totshrink;
  728.         if (eat_glue) {*(in+i)=3; *(in+ ++i)=tolong(0);i+=2;break;}
  729.         cx += tofloat(*(in+ ++i));
  730.         totstretch += tofloat(*(in+ ++i));
  731.         totshrink += tofloat(*(in+ ++i));
  732.         dbg gprint("total stretch %f, shrink %f \n",totstretch,totshrink);
  733.         break;
  734.         case 3: /* move     x,0,0   SOLID   */
  735.         cx += tofloat(*(in+ ++i));
  736.         i += 2;
  737.         ax = cx;
  738.         eat_glue = false;
  739.         break;
  740.         case 4: /* move     x,y     SOLID   */
  741.         eat_glue = false;
  742.         cx += tofloat(*(in+ ++i));
  743.         cy += tofloat(*(in+ ++i));
  744.         ax = cx;
  745.         break;
  746.         case 5: /* Newline  x,y     (0,0 at moment) */
  747.         case 10:
  748.         if (*(in+i)==5) skline = true; else skline = false;
  749.         *(in+i) = 0;
  750. /*              last_space = i;
  751.         last_x = ax;
  752.         last_y = cy;
  753.         last_stret = totstretch;
  754.         last_shrink = totshrink;
  755. */
  756.           if (last_space<=si || ax==cx) {
  757.             last_x = ax;
  758.             last_y = cy;
  759.             last_stret = totstretch;
  760.             last_shrink = totshrink;
  761.             last_space = i;
  762.           }
  763.             dbg gprint("Call SET_GLUE  from %d, to %d \n",si,last_space);
  764.             set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
  765.             saveii = i;
  766.             i = last_space;
  767.             while (i < saveii) *(in+i++) = 20; /* nop */
  768.             *(in+i++) = 4;
  769.             *(in+i++) = tolong(-setlen);
  770.             if (pcr!=NULL) { /* put in last line feed now */
  771.                 y = last_y-ls;
  772.                 if ((y+chei+gap)>lastdep)
  773.                     y = lastdep-chei-gap;
  774.                 cy = y;
  775.                 *pcr = tolong(y);
  776.             }
  777.             if (skline)
  778.                 font_get_lineskip(&ls,&gap);
  779.             else    font_get_parskip(&ls,&gap);
  780.             pcr = (in+i);   /* place to put line feed */
  781.             last_stret = 0;
  782.             last_shrink = 0;
  783.             totstretch = 0;
  784.             totshrink = 0;
  785.             lastdep = cdep;
  786.             last_y = cy;
  787.             cx = 0;
  788.             cy = 0;
  789.             si = i+1;
  790.             eat_glue = true;
  791.             break;
  792. /*              eat_glue = true;
  793.         i += 2;
  794.         break; */
  795.         case 6: /* rule     x,y             */
  796.         i += 2;
  797.         eat_glue = false;
  798.         break;
  799.         case 7: /* color    color           */
  800.         g_set_color(tofloat(*(in+ ++i)));
  801.         break;
  802.         case 8: /* fontsz   sz              */
  803.         p_hei = tofloat(*(in+ ++i));
  804.         g_set_hei(p_hei);
  805.         break;
  806.         case 9: /* font     p_fnt   */
  807.         p_fnt = *(in+ ++i);
  808.         font_load_metric(p_fnt);
  809.  
  810.         break;
  811.         case 20: /*  nop  */
  812.         break;
  813.         default:
  814.         gprint("dud pcode in wrap pcode %d   i=%d \n",*(in+i),i);
  815.         break;
  816.       }
  817.     }
  818.  
  819.     if (last_space==0) last_space = ilen;
  820.     dbg gprint("Exiting call to SET_GLUE  from %d, to %d \n",si,last_space);
  821.     set_glue(in+si,last_space-si,last_x,width,last_stret,last_shrink,&setlen);
  822.     if (pcr!=NULL) { /* put in last line feed now */
  823.         y = last_y-ls;
  824.         if ((y+chei+gap)>lastdep)
  825.             y = lastdep-chei-gap;
  826.         cy = y;
  827.         *pcr = tolong(y);
  828.     }
  829.     dbg text_gprint(in,ilen);
  830. }
  831. set_glue(int32 *in,int ilen,double actual,double width,double stretch,double
  832.     shrink,double *setlen)
  833. {
  834.     double mst=0,msh=0;
  835.     float s1,s2,x,y;
  836.     int i=0;
  837.  
  838.     dbg gprint("===set glue \n");
  839.     dbg text_gprint(in,ilen);
  840.     dbg gprint("set glue ilen=%d actual=%f, width=%f, stretch=%f shrink=%f \n"
  841.             ,ilen,actual,width,stretch,shrink);
  842. /*      if (actual<0) get_natural(in,ilen,&actual); */
  843.     if (actual<width) {
  844.         if (stretch>0.0000001) mst = (width-actual)/stretch;
  845.         msh = 0;
  846.         if (mst>1) mst=0;
  847.     } else {
  848.         mst = 0;
  849.         if (shrink>0) msh = (actual-width)/shrink;
  850.         if (msh>1) msh=0;
  851.     }
  852.     *setlen = actual+stretch*mst+shrink*msh;
  853.     dbg gprint("SETTing glue to  %f  %f  actual %f, setto %f\n",mst,msh,actual,*setlen);
  854.  
  855.     for (i=0;i<ilen;i++) {
  856.       switch (*(in+i)) {
  857.         case 1: /* char     font+char,wx    */
  858.         i += 2;
  859.         break;
  860.         case 2: /* move     x,stretch,shrink */
  861.         x = tofloat(*(in+i+1));
  862.         s1 = tofloat(*(in+i+2));
  863.         s2 = tofloat(*(in+i+3));
  864.         *(in+i) = 3;
  865.         *(in+i+1) = tolong(x + s1*mst+s2*msh);
  866.         i += 3;
  867.         break;
  868.         case 3: /* move     x,0,0   SOLID   */
  869.         i += 3;
  870.         break;
  871.         case 4: /* move     x,y     SOLID   */
  872.         i += 2;
  873.         break;
  874.         case 5: /* Newline  x,y     (0,0 at moment) */
  875.         i += 2;
  876.         break;
  877.         case 6: /* rule     x,y             */
  878.         i += 2;
  879.         break;
  880.         case 7: /* color    color           */
  881.         i += 1;
  882.         break;
  883.         case 8: /* fontsz   sz              */
  884.         i += 1;
  885.         break;
  886.         case 9: /* font     p_fnt   */
  887.         i += 1;
  888.         break;
  889.         case 10: /* Newparagraph x,y        (0,0 at moment) */
  890.         i += 2;
  891.         break;
  892.         case 20: /*  nop  */
  893.         break;
  894.         default:
  895.         gprint("dud (in set glue) pcode in text pcode %d i=%d\n",*(in+i),i);
  896.         break;
  897.       }
  898.     }
  899.     dbg printf("=== Result after setting \n");
  900.     dbg text_gprint(in,ilen);
  901.     dbg printf("===+++++ END OF SET GLUE  =============== \n");
  902. }
  903.  
  904. text_draw(int32 *in,int ilen)
  905. {
  906.     double cx,cy,p_hei,x,y;
  907.     int i,c,p_fnt;
  908.  
  909.     dbg gprint("---TEXT DRAW, ilen = %d \n",ilen);
  910.     dbg text_gprint(in,ilen);
  911.     cx = 0;
  912.     cy = 0;
  913.     dp g_get_xy(&cx,&cy);
  914.     dbg printf("Current x y, %g %g \n",cx,cy);
  915.     p_hei = 1;
  916.  
  917.     for (i=0;i<ilen;i++) {
  918.       switch (*(in+i)) {
  919.         case 1: /* char     font+char,wx    */
  920.         p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
  921.         font_load_metric(p_fnt);
  922.  
  923.         c = *(in+i) & 0x00ff;
  924.         g_set_bounds(cx+p_hei*((*(fnt[p_fnt].chr))[c].x1),cy+p_hei*((*(fnt[p_fnt].chr))[c].y1));
  925.         g_set_bounds(cx+p_hei*((*(fnt[p_fnt].chr))[c].x2),cy+p_hei*((*(fnt[p_fnt].chr))[c].y2));
  926.         dp {
  927.             g_move(cx,cy);
  928.             g_char(p_fnt,c);
  929.         }
  930.         cx += tofloat(*(in+ ++i));
  931.         break;
  932.         case 2: /* move     x,stretch,shrink */
  933.         cx += tofloat(*(in+ ++i));
  934.         i += 2;         /* glue is already set */
  935.         break;
  936.         case 3: /* move     x,0,0   SOLID   */
  937.         cx += tofloat(*(in+ ++i));
  938.         i += 2;
  939.         break;
  940.         case 4: /* move     x,y     SOLID   */
  941.         cx += tofloat(*(in+ ++i));
  942.         cy += tofloat(*(in+ ++i));
  943.         break;
  944.         case 5: /* Newline  x,y     (turned into a move) */
  945.         i += 2;
  946.         break;
  947.         case 6: /* rule     x,y             */
  948.         x = tofloat(*(in+ ++i));
  949.         y = tofloat(*(in+ ++i));
  950.         g_set_bounds(cx,cy);
  951.         g_set_bounds(cx+x,cy+y);
  952.         if (x>0) g_box_fill(cx,cy,cx+x,cy+y);
  953.         break;
  954.         case 7: /* color    color           */
  955. /*              dp g_set_color(tofloat(*(in+ ++i)));*/
  956.         break;
  957.         case 8: /* fontsz   sz              */
  958.         p_hei = tofloat(*(in+ ++i));
  959.         g_set_hei(p_hei);
  960.         break;
  961.         case 9: /* font     p_fnt   */
  962.         p_fnt = *(in+ ++i);
  963.         font_load_metric(p_fnt);
  964.  
  965.         break;
  966.         case 10: /* Newline  x,y    (turned into a move) */
  967.         i += 2;
  968.         break;
  969.         case 20: /*  nop  */
  970.         break;
  971.         case 0:
  972.         dbg gprint("zero");
  973.         break;
  974.         default:
  975.         gprint("dud3 pcode in text pcode %d %d \n",*(in+i),i);
  976.         break;
  977.       }
  978.     }
  979.     text_endx = cx;
  980.     text_endy = cy;
  981.     dbg gprint("---TEXT DRAW, DONE. %g %g \n",cx,cy);
  982. }
  983. double tex_xend(void)
  984. {
  985.     return text_endx;
  986. }
  987. double tex_yend(void)
  988. {
  989.     return text_endy;
  990. }
  991. text_gprint(int32 *in,int ilen)
  992. {
  993.     double cx,cy,p_hei,x,y;
  994.     int i,c,p_fnt,z;
  995.  
  996.     for (i=0;i<ilen;i++) printf("%lx ",*(in+i));
  997.     printf("\n");
  998.     z=0;
  999.     printf("# ");
  1000.     for (i=0;i<ilen;i++) {
  1001.       switch (*(in+i)) {
  1002.         case 1: /* char     font+char,wx    */
  1003.         p_fnt = (*(in+ ++i) & 0xff00) / 0x100;
  1004.         font_load_metric(p_fnt);
  1005.  
  1006.         c = *(in+i) & 0x00ff;
  1007.         x = tofloat(*(in+ ++i));
  1008.         printf("%c[%3.3h]",c,x);
  1009.     /*      printf("%c{%d %3.3f} ",c,p_fnt,tofloat(*(in+ ++i)));  */
  1010.         break;
  1011.         case 2: /* move     x,stretch,shrink */
  1012.         printf("[sp %3.3f %3.3f %3.3f] \n# ",tofloat(*(in+1+i))
  1013.                 ,tofloat(*(in+2+i)),tofloat(*(in+3+i)));
  1014.         i += 3;
  1015.         break;
  1016.         case 3: /* move     x,0,0   SOLID   */
  1017.         printf("(3 %3.3f %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
  1018.                 ,tofloat(*(in+2+i)),tofloat(*(in+3+i)));
  1019.         i += 3;
  1020.         break;
  1021.         case 4: /* move     x,y     SOLID   */
  1022.         printf("(4 %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
  1023.                 ,tofloat(*(in+2+i)));
  1024.         i += 2;
  1025.         break;
  1026.         case 5: /* Newline  x,y     (turned into a move) */
  1027.         i += 2;
  1028.         printf("5 \n# ");
  1029.         break;
  1030.         case 6: /* rule     x,y             */
  1031.         printf("(rule %3.3f %3.3f) \n# ",tofloat(*(in+1+i))
  1032.                 ,tofloat(*(in+2+i)));
  1033.         i += 2;
  1034.         break;
  1035.         case 7: /* color    color           */
  1036.         printf("(color %x) \n# ",(*(in+ ++i)));
  1037.         break;
  1038.         case 8: /* fontsz   sz              */
  1039.         printf("(p_hei %3.3f) \n# ",tofloat(*(in+ ++i)));
  1040.         break;
  1041.         case 9: /* font     p_fnt   */
  1042.         printf("(font %d) \n",(*(in+ ++i)));
  1043.         break;
  1044.         case 10: /* Newline  x,y    (turned into a move) */
  1045.         i += 2;
  1046.         printf("\n10(paragraph)\n# ");
  1047.         break;
  1048.         case 20: /*  nop  */
  1049.         printf("NOP ");
  1050.         break;
  1051.         default:
  1052.         printf("(err=%4x pos=%d)\n ",*(in+i),i);
  1053.         break;
  1054.       }
  1055.     }
  1056.     printf("\n");
  1057. }
  1058. double lineskip1,parskip1;
  1059. font_reset_parskip()
  1060. {
  1061.     lineskip1 = 1.0;
  1062.     parskip1 = 2.5;
  1063. }
  1064. set_parskip(double v)
  1065. {
  1066.     parskip1 = v;
  1067. }
  1068. set_lineskip(double v)
  1069. {
  1070.     lineskip1 = v;
  1071. }
  1072. font_get_lineskip(double *ls,double *gap)
  1073. {
  1074.     *ls = p_hei * lineskip1;
  1075.     *gap = *ls * .1 + linegap;
  1076. }
  1077. font_get_parskip(double *ls,double *gap)
  1078. {
  1079.     *ls = p_hei * parskip1;
  1080.     *gap = *ls * .1;
  1081. }
  1082.  
  1083. int pass_font(char *p)
  1084. {
  1085.     int i,f=0,etype=1;
  1086.     int32 j;
  1087.     char u[90];
  1088.     char vv[80],*s;
  1089.     double xx;
  1090.  
  1091.     s = &u[0];
  1092.     strncpy(u,p,90);
  1093.     strupr(u);
  1094.     if ( (*s=='"')  || (strchr(s,'$') != NULL)) {
  1095.         strcpy(vv,"cvtfont(");
  1096.         strcat(vv,s); strcat(vv,")");
  1097.         polish_eval(vv,&xx);
  1098.         memcpy(&j,&xx,sizeof(int32));
  1099.         return j;  /* actyally is an int */
  1100.     } else {
  1101.         if (nfnt==0) font_load();
  1102.         for (i=1; i<=nfnt; i++) {
  1103.             if (fnt[i].name!=NULL) if (strcmp(fnt[i].name,u)==0) {
  1104.               return i;
  1105.             }
  1106.         }
  1107.         gprint("Invalid font name {%s}, NFNT %d expecting one of: \n    ",u,nfnt);
  1108.         for (i=1;i<=nfnt; i++) {
  1109.             if (fnt[i].name!=NULL)
  1110.                 gprint("  {%s} ",fnt[i++].name);
  1111.             if (fnt[i].name!=NULL)
  1112.                 gprint("  {%s} ",fnt[i++].name);
  1113.             if (fnt[i].name!=NULL)
  1114.                 gprint("  {%s} ",fnt[i++].name);
  1115.             if (fnt[i].name!=NULL)
  1116.                 gprint("  {%s} \n",fnt[i].name);
  1117.         }
  1118.         return 1;       /* default font number */
  1119.     }
  1120. }
  1121. #define get_exps(ss) polish(ss,(char *) pcode,plen,&etype)
  1122. #define tok(n)  (*tk)[n]
  1123. get_font(char (*(*tk)[500]),int *ntok,int *curtok,int32 *pcode,int *plen)
  1124. {
  1125.     int i,f=0,etype=1;
  1126.     char vv[80];
  1127.     char *p;
  1128.     if (nfnt==0) font_load();
  1129.  
  1130.     if ( (*tok(*curtok)=='"') ||  (strchr(tok(*curtok),'$') != NULL) ) {
  1131.         strcpy(vv,"cvtfont(");
  1132.         strcat(vv,tok(*curtok)); strcat(vv,")");
  1133.         get_exps(vv);
  1134.         (*curtok)++;
  1135.         return;
  1136.     }
  1137.  
  1138.     p = (*tk)[*curtok];
  1139.     (*curtok)++;
  1140.     *(pcode+(*plen)++) = 8;
  1141.     for (i=1; i<=nfnt; i++) {
  1142.         if (fnt[i].name!=NULL) if (strcmp(fnt[i].name,p)==0) {
  1143.           *(pcode+(*plen)++) = i;       /* font number */
  1144.           return;
  1145.         }
  1146.     }
  1147.     gprint("Invalid font name {%s}, expecting one of: \n    ",p);
  1148.     for (i=1;i<=nfnt; i++) {
  1149.         if (fnt[i].name!=NULL)
  1150.             gprint("  {%s} ",fnt[i++].name);
  1151.         if (fnt[i].name!=NULL)
  1152.             gprint("  {%s} ",fnt[i++].name);
  1153.         if (fnt[i].name!=NULL)
  1154.             gprint("  {%s} ",fnt[i++].name);
  1155.         if (fnt[i].name!=NULL)
  1156.             gprint("  {%s} \n",fnt[i].name);
  1157.     }
  1158.     *(pcode+(*plen)++) = 1;         /* default font number */
  1159. }
  1160. text_block(uchar *s,double width,int justify)
  1161. {
  1162.     double ox,oy,x,y,ll,rr,uu,dd;
  1163.     double a,b,c,d;
  1164.  
  1165.     set_base_size();
  1166.     g_get_bounds(&a,&b,&c,&d);
  1167.     g_init_bounds();
  1168.     dont_print = true;
  1169.     fftext_block(s,width,justify);
  1170.     dont_print = false;
  1171.     g_get_bounds(&ll,&dd,&rr,&uu);
  1172.     if (ll > rr) {ll=0; rr=0; uu=0; dd=0;}
  1173.     g_get_xy(&ox,&oy);
  1174.     x = ox; y = oy;
  1175.     g_dotjust(&x,&y,ll,rr,uu,dd,justify);
  1176.     g_move(x,y);
  1177.     g_init_bounds();
  1178.     if (a<=c) {
  1179.         g_set_bounds(a,b);
  1180.         g_set_bounds(c,d);
  1181.     }
  1182.     g_get_bounds(&a,&b,&c,&d);
  1183.     text_draw(gt_pbuff,gt_plen);
  1184.     g_get_bounds(&a,&b,&c,&d);
  1185.     g_move(ox,oy);
  1186. }
  1187. /*----------------------------------------------------------------------*/
  1188. /* Searches CMD and replaces #n's with parameters */
  1189. char *tex_replace(char *cmd,char *pm[],int pmlen[],int npm)
  1190. {
  1191.     char *r,*s,*o;
  1192.     int n,i;
  1193.  
  1194. /*      printf("replace {%s} \n",cmd);
  1195.     for (i=0;i<npm;i++) {
  1196.         printf("pm[%d] = {%s} %d \n",i,pm[i],pmlen[i]);
  1197.     }
  1198. */
  1199.     if (strchr(cmd,'#')==0) return sdup(cmd);
  1200.     r = myalloc(1000);
  1201.     o = r;
  1202.     for (s=cmd; *s!=0; s++) {
  1203.         if (*s=='#') {
  1204.             n = *(++s) - '0';
  1205.             if (n>0 && n<=npm) {
  1206.                 strncpy(o,pm[n-1],pmlen[n-1]);
  1207.                 o += pmlen[n-1];
  1208.             }
  1209.         } else *o++ = *s;
  1210.     }
  1211.     *o++ = 0;
  1212.     return r;
  1213. }
  1214.  
  1215. /*----------------------------------------------------------------------*/
  1216. /*              tex_chardef                                             */
  1217. /*----------------------------------------------------------------------*/
  1218. tex_chardef(int c, char *defn)  /* Defines single char as string */
  1219. {
  1220.     if (c<0 || c>255) return;
  1221.     if (cdeftable[c]!=NULL) myfree(cdeftable[c]);
  1222.     cdeftable[c] = sdup(defn);
  1223. }
  1224. char *tex_findchardef(int c)
  1225. {
  1226.     return cdeftable[c];
  1227. }
  1228.  
  1229. /*----------------------------------------------------------------------*/
  1230. /*              Hashing table code for \def                             */
  1231. /*----------------------------------------------------------------------*/
  1232. #define HASHSIZE 101
  1233.  
  1234. static deftable  *def_hashtab[HASHSIZE];
  1235.  
  1236. unsigned hash_str(char *s);
  1237. unsigned hash_str(char *s)
  1238. {
  1239.     unsigned hashval;
  1240.  
  1241.     for (hashval=0; *s != 0; s++)
  1242.         hashval = *s + 31*hashval;
  1243.     return hashval % HASHSIZE ;
  1244. }
  1245.  
  1246. deftable *tex_finddef(char *s)
  1247. {
  1248.     deftable  *np;
  1249.  
  1250.     for (np = def_hashtab[hash_str(s)]; np != NULL; np = np->next)
  1251.         if (strcmp(s, np->name) == 0) {
  1252.             return np;
  1253.         }
  1254.     return NULL;
  1255. }
  1256.  
  1257. tex_def(char *name, char *defn,int npm)
  1258. {
  1259.     deftable  *np;
  1260.     char **s;
  1261.     unsigned hashval;
  1262.  
  1263.     if ((np = tex_finddef(name)) == NULL) { /* not found */
  1264.         np = (deftable  *) myalloc(sizeof(*np));
  1265.         if ((np == NULL) || (np->name = sdup(name)) == NULL)
  1266.             return NULL;
  1267.         hashval = hash_str(name);
  1268.         np->next = def_hashtab[hashval];
  1269.         def_hashtab[hashval] = np;
  1270.         np->npm = npm;
  1271.         if ((np->defn = sdup(defn)) == NULL) return NULL;
  1272.     } else {
  1273.         myfree(np->defn);
  1274.         if ((np->defn = sdup(defn)) == NULL) return NULL;
  1275.     }
  1276.     return true;
  1277. }
  1278. /*----------------------------------------------------------------------*/
  1279. /*              Hashing table code for \mathchardef                     */
  1280. /*----------------------------------------------------------------------*/
  1281. struct mdef_table_struct {
  1282.     struct mdef_table_struct  *next;
  1283.     char *name;
  1284.     int defn;
  1285. };
  1286. typedef struct mdef_table_struct mdeftable;
  1287.  
  1288. static mdeftable  *mdef_hashtab[HASHSIZE];
  1289.  
  1290. int *tex_findmathdef(char *s)
  1291. {
  1292.     mdeftable  *np;
  1293.  
  1294.     for (np = mdef_hashtab[hash_str(s)]; np != NULL; np = np->next)
  1295.         if (strcmp(s, np->name) == 0) {
  1296.             return &np->defn;
  1297.         }
  1298.     return NULL;
  1299. }
  1300.  
  1301. tex_mathdef(char *name, int defn)
  1302. {
  1303.     mdeftable  *np;
  1304.     int *d;
  1305.     unsigned hashval;
  1306.  
  1307.     if ((d = tex_findmathdef(name)) == NULL ) { /* not found */
  1308.         np = (mdeftable  *) myalloc(sizeof(*np));
  1309.         if ((np == NULL) || (np->name = sdup(name)) == NULL)
  1310.             return NULL;
  1311.         hashval = hash_str(name);
  1312.         np->next = mdef_hashtab[hashval];
  1313.         mdef_hashtab[hashval] = np;
  1314.         np->defn = defn;
  1315.     } else {
  1316.         *d = defn;
  1317.     }
  1318.     return true;
  1319. }
  1320. tex_init()
  1321. {
  1322.     int i;
  1323.     for (i=0;i<256;i++) chr_val[i]=i;
  1324.     for (i=0;i<256;i++) chr_code[i]=10;     /* other */
  1325.     for (i=65;i<91;i++) chr_code[i]=1;      /* alpha */
  1326.     for (i=97;i<123;i++) chr_code[i]=1;
  1327.     chr_code[0] = 2; /* maybe should be 0,  this is only tested in lig*/
  1328.     chr_code[' '] = 2;
  1329.     chr_code[9] = 2;
  1330.     chr_code['\n'] = 2;
  1331.     chr_code['\\'] = 6;
  1332.     chr_code['{'] = 7;
  1333.     chr_code['}'] = 8;
  1334.     chr_code[255] = 11;     /* flag for end of paragraph, unless verbatim */
  1335.     chr_init = true;
  1336.     tex_preload();
  1337.     tex_def(" ","\\movexy{1sp}{}",0);
  1338.     tex_def("\\","\\newline",0);
  1339.     tex_def("{","\\char{123}",0);
  1340.     tex_def("}","\\char{125}",0);
  1341.     tex_def("_","\\char{95}",0);
  1342.     /* tex_def("^","\\char{94}",0); */
  1343.     tex_def("$","\\char{36}",0);
  1344. }
  1345. tex_clear()
  1346. {
  1347.     /* clear CHARDEF table before each redraw */
  1348.  
  1349.     int c;
  1350.     for (c=1;c<255;c++) {
  1351.         if (cdeftable[c]!=NULL) {
  1352.             myfree(cdeftable[c]);
  1353.             cdeftable[c] = NULL;
  1354.         }
  1355.     }
  1356.     tex_chardef('^',"\\sup ");
  1357.     tex_chardef('_',"\\sub ");
  1358. }
  1359. g_measure(char *s, double *l, double *r, double *u, double *d)
  1360. {
  1361.     double sa,sb,sc,sd;
  1362.     g_get_bounds(&sa,&sb,&sc,&sd);
  1363.     set_base_size();
  1364.     g_init_bounds();
  1365.     dont_print = true;
  1366.     fftext_block(UC s,0.0,0);
  1367.     dont_print = false;
  1368.     g_get_bounds(l,d,r,u);
  1369.     if (*l > *r) {*l=0; *r=0; *u=0; *d=0;}
  1370.     gt_l = *l;
  1371.     gt_r = *r;
  1372.     gt_u = *u;
  1373.     gt_d = *d;
  1374.     g_init_bounds();
  1375.     if (sa>sc) return;
  1376.     g_set_bounds(sa,sb);
  1377.     g_set_bounds(sc,sd);
  1378. }
  1379. g_textfindend(char *s, double *cx, double *cy)
  1380. {
  1381.     double sa,sb,sc,sd;
  1382.     set_base_size();
  1383.     g_get_bounds(&sa,&sb,&sc,&sd);
  1384.     dont_print = true;
  1385.     fftext_block(UC s,0.0,0);
  1386.     *cx = text_endx;
  1387.     *cy = text_endy;
  1388.     dont_print = false;
  1389.     g_init_bounds();
  1390.     if (sa>sc) return;
  1391.     g_set_bounds(sa,sb);
  1392.     g_set_bounds(sc,sd);
  1393. }
  1394. g_jtext(int just)
  1395. {
  1396.     double ox,oy,x,y;
  1397.     g_get_xy(&ox,&oy);
  1398.     x = ox; y = oy;
  1399.     g_dotjust(&x,&y,gt_l,gt_r,gt_u,gt_d,just);
  1400.     g_move(x,y);
  1401.     text_draw(gt_pbuff,gt_plen);
  1402.     g_move(ox,oy);
  1403. }
  1404. static uchar tbuff[8000];
  1405. text_def(uchar *s)
  1406. {
  1407.     gt_plen = 0;
  1408.     if (chr_init==false) tex_init();
  1409.     text_topcode(s,gt_pbuff,>_plen);
  1410. }
  1411. fftext_block(uchar *s,double width,int justify)
  1412. {
  1413.     uchar *t,*r,*m,*p;
  1414.     int i;
  1415.  
  1416.     g_get_font(&p_fnt);
  1417.     font_load_metric(p_fnt);
  1418.  
  1419.     g_get_hei(&p_hei);
  1420.     font_reset_parskip();
  1421.     gt_plen = 0;
  1422.     if (s==NULL) {
  1423.         dbg gprint("TEXT_BLOCK, Passed NULL pointer \n");
  1424.         return;
  1425.     }
  1426.     if (*s==0) {
  1427.         /* gprint("TEXT_BLOCK, Passed empty string \n"); */
  1428.         return;
  1429.     }
  1430.     if (chr_init==false) tex_init();
  1431. lp:
  1432.  
  1433.     t = UC strstr(SC s,"\n\n");     /* search for cr,cr                     */
  1434.     if (t!=NULL) {
  1435.         *(t+1) = 255;   /* flag end of paragraph */
  1436.         goto lp;
  1437.     }
  1438.     text_tomacro(s,tbuff);
  1439.     gt_plen = 0;
  1440.     if (width==0) {
  1441.         width = 400;
  1442.         chr_code['\n'] = 5;
  1443.     } else chr_code['\n'] = 2;
  1444.     text_topcode(tbuff,gt_pbuff,>_plen);
  1445.     text_wrapcode(gt_pbuff,gt_plen,width);
  1446.     text_draw(gt_pbuff,gt_plen);
  1447.  
  1448.  
  1449.     g_set_font(p_fnt);
  1450.     g_set_hei(p_hei);
  1451.  
  1452.  
  1453. /*      dbg gprint("text to macro {%s} {%s} \n",s,tbuff);
  1454.     dbg gprint("============topcode \n");
  1455.     dbg gprint("P: ");
  1456.     for (i=0;i<plen;i++) {
  1457.         dbg gprint("%4x ",pbuff[i]);
  1458.         if ((i+1)/10==(i+1)/10.0) dbg gprint("\nP: ");
  1459.     }
  1460.     dbg gprint("\n");
  1461.     dbg text_gprint(pbuff,plen);
  1462.     dbg gprint("\n");
  1463.     dbg gprint("==== ====       ==== ==== wrapcode \n");
  1464.     dbg gprint("\n");
  1465.     dbg gprint("==== ====       ==== ==== draw \n");
  1466. */
  1467. }
  1468. cmd_token(uchar **in,char *cmdstr)
  1469. {
  1470.     int gcnt,i;
  1471.     char *s;
  1472.     s = cmdstr;
  1473.     i=0;
  1474.     if ( (!isalpha(**in)) && (**in != 0)) {
  1475.         *cmdstr++ = *(*in)++;
  1476.     } else {
  1477.         for (; chr_code[**in]==1 && **in != 0 && i<20;(*in)++,i++)  {
  1478.             *cmdstr++ = **in;
  1479.         }
  1480.     }
  1481.     *cmdstr = 0;
  1482.     cmdstr -= 1;
  1483.     if (chr_code[*cmdstr]==1) {
  1484.         for (;(**in != 0) && (chr_code[**in]==2);) (*in)++;
  1485.     }
  1486. }
  1487. text_tomacro(uchar *in, uchar *out)
  1488. {
  1489.     /* find /cmdname  or defined characters */
  1490.     static char macroname[30];
  1491.     uchar *s,*dfn,*r,*saves;
  1492.     int changed,dlen;
  1493.     int nrep,j;
  1494.     deftable  *np;
  1495.     static union {char *s[10]; uchar *u[10];} pm;
  1496.     static int pmlen[10];
  1497.  
  1498.     nrep = 0;
  1499.     strcpy(SC out,SC in);
  1500.     for (s=out; *s != 0;s++)  {
  1501.       if (nrep>300) gle_abort("Loop in text macros\n");
  1502.       if (chr_code[*s]==6) {        /* backslash, begining of macro? */
  1503.         saves = s;
  1504.         s++;
  1505.         cmd_token(&s,macroname);
  1506.         np = tex_finddef(macroname);
  1507.         if (np != NULL) {
  1508.             nrep++;
  1509.             dfn = UC np->defn;
  1510.             dbg printf("Found macro {%s} = {%s} \n",macroname,dfn);
  1511.             cmd_param(&s,pm.u,pmlen,np->npm);
  1512.             dlen = s-saves;
  1513.             r = UC tex_replace(SC dfn,pm.s,pmlen,np->npm);
  1514.             s = saves;
  1515.             memmove(SC s+strlen(SC r),SC s+dlen,strlen(SC s)+1);
  1516.             strncpy(SC s,SC r,strlen(SC r));
  1517.             myfree(r);
  1518.             s--;
  1519.         }
  1520.         s = saves;
  1521.       }
  1522.       if (cdeftable[*s]!=0) {
  1523.         dbg printf("Found char definition %d  {%s} \n",*s,s);
  1524.         nrep++;
  1525.         dfn = UC tex_findchardef(*s);
  1526.         memmove(s+strlen(SC dfn)-1,s,strlen(SC s)+1);
  1527.         strncpy(SC s,SC dfn,strlen(SC dfn));
  1528.         s--;
  1529.       }
  1530.     }
  1531.     dbg printf("MACOR IN {%s} \n",in);
  1532.     dbg printf("MACOR CODE {%s} \n",out);
  1533. }
  1534. tex_presave()
  1535. {
  1536.     int i;
  1537.     deftable *dt;
  1538.     FILE *fout;
  1539.     mdeftable *mdt;
  1540.     char *workarea;
  1541.     /* Save all defined features possible */
  1542.     fout = fopen(gledir("inittex.ini"),WRITE_BIN);
  1543.     if (fout==NULL) gprint("Could not open inittex.ini file \n");
  1544.     fwrite(fontfam,sizeof(int),16*4,fout);
  1545.     fwrite(fontfamsz,sizeof(double),16*4,fout);
  1546.     fwrite(chr_mathcode,sizeof(char),256,fout);
  1547.  
  1548.     for (i=0;i<HASHSIZE;i++) {
  1549.       for (dt = def_hashtab[i]; dt != NULL; dt = dt->next) {
  1550.         fwrite(&i,sizeof(i),1,fout);
  1551.         fwrite(&dt->npm,sizeof(i),1,fout);
  1552.         fsendstr(dt->name,fout);
  1553.         fsendstr(dt->defn,fout);
  1554.       }
  1555.     }
  1556.     i = 0x0fff; fwrite(&i,sizeof(i),1,fout);
  1557.     for (i=0;i<HASHSIZE;i++) {
  1558.       for (mdt = mdef_hashtab[i]; mdt != NULL; mdt = mdt->next) {
  1559.         fwrite(&i,sizeof(i),1,fout);
  1560.         fwrite(&mdt->defn,sizeof(i),1,fout);
  1561.         fsendstr(mdt->name,fout);
  1562.       }
  1563.     }
  1564.     i = 0x0fff; fwrite(&i,sizeof(i),1,fout);
  1565.     for (i=0;i<256;i++)  fsendstr(cdeftable[i],fout);
  1566.     fclose(fout);
  1567. }
  1568. /*----------------------------------------------------------------------*/
  1569. fgetvstr(char **s,FILE *fmt)
  1570. {
  1571.     int i;
  1572.     i = fgetc(fmt);
  1573.     if (i==0) return;
  1574.     *s = myalloc(i+1);
  1575.     fread(*s,1,i,fmt);
  1576.     *(*s+i) = 0;
  1577. }
  1578. fgetcstr(char s[],FILE *fmt)
  1579. {
  1580.     int i;
  1581.     i = fgetc(fmt);
  1582.     if (i==0) return;
  1583.     fread(s,1,i,fmt);
  1584.     s[i] = 0;
  1585. }
  1586. fsendstr(char *s,FILE *fout)
  1587. {
  1588.     if (s==NULL) {
  1589.         fputc(0,fout);
  1590.         return;
  1591.     }
  1592.     fputc(strlen(s),fout);
  1593.     fwrite(s,1,strlen(s),fout);
  1594. }
  1595. tex_preload()
  1596. {
  1597.     int i,j;
  1598.     deftable *dt;
  1599.     FILE *fout;
  1600.     mdeftable *mdt;
  1601.     char *workarea;
  1602.     char str1[80],str2[80];
  1603.     /* reload all defined features */
  1604.     fout = fopen(gledir("inittex.ini"),READ_BIN);
  1605.     if (fout==NULL) {gprint("Could not open inittex.ini file \n"); return;}
  1606.     fread(fontfam,sizeof(int),16*4,fout);
  1607.     fread(fontfamsz,sizeof(double),16*4,fout);
  1608.     fread(chr_mathcode,sizeof(char),256,fout);
  1609.  
  1610.     for (;  (fread(&i,sizeof(i),1,fout)), i != 0x0fff;) {
  1611.         fread(&j,sizeof(j),1,fout);
  1612.         fgetcstr(str1,fout); fgetcstr(str2,fout);
  1613.         tex_def(str1,str2,j);
  1614.     }
  1615.     for (;  (fread(&i,sizeof(i),1,fout)), i != 0x0fff;) {
  1616.         fread(&j,sizeof(j),1,fout);
  1617.         fgetcstr(str1,fout);
  1618.         tex_mathdef(str1,j);
  1619.     }
  1620.  
  1621.     for (i=0;i<256;i++)  fgetvstr(&cdeftable[i],fout);
  1622.     fclose(fout);
  1623. }
  1624.